昨天我們幫服務加上 /metrics,終於能看見完整的角色面板:血條、藍條、技能冷卻都一清二楚。
但問題來了:
你總不能每天盯著 /metrics 網頁,像刷股票行情一樣看數字吧?
就算你是爆肝工程師,眼睛盯 24/7 ,薪水不會比較多,也可能錯過瞬間的暴擊。
真正的關鍵是:讓系統自己在快掛的時候喊救命。
這就是今天的主角 —— 監控 (Monitoring) 與告警 (Alerting)。
Metrics 本質上就是一堆數字。
單看它們,就像你打開 Excel,看見 CPU=87%、Mem=2.3GB、Request=1234。
然後呢?
缺少的東西是「規則」與「動作」:
沒有這層轉換,metrics 只是一堆靜態數字;有了這層轉換,它才變成可以拯救系統的訊號。
就像遊戲裡不是只看血條,而是要在血量 < 30% 時自動播放語音:
「補師快補!坦克開嘲諷拉怪!」

在現實世界,最常見的組合是:
流程長這樣:
在專案根目錄
(a) docker-compose.monitor.yml
把 Prometheus + Alertmanager 一起起來(可和你的 app 分開跑)
services:
  prometheus:
    image: prom/prometheus:v2.53.0
    container_name: mon-prometheus
    ports:
      - "9090:9090"
    volumes:
      - ./monitoring/prometheus.yml:/etc/prometheus/prometheus.yml:ro
      - ./monitoring/alert.rules.yml:/etc/prometheus/alert.rules.yml:ro
    command:
      - "--config.file=/etc/prometheus/prometheus.yml"
      - "--web.enable-lifecycle"     # 允許熱重載 /-/reload
    networks: [web]
    depends_on:
      - alertmanager
  alertmanager:
    image: prom/alertmanager:v0.27.0
    container_name: mon-alertmanager
    ports:
      - "9093:9093"
    volumes:
      - ./monitoring/alertmanager.yml:/etc/alertmanager/alertmanager.yml:ro
    environment:
      GMAIL_APP_PASSWORD: '${GMAIL_APP_PASSWORD}'
      ENVIRONMENT: prod
    command:
      - "--config.file=/etc/alertmanager/alertmanager.yml"
      - "--log.level=info"
    networks: [web]
networks:
  web: {}   # 與主 compose 的 web 同名即可,Compose 會合併
(b) monitoring/prometheus.yml
Prometheus 抓你的服務 + 報警丟給 Alertmanager。
global:
  scrape_interval: 15s
  evaluation_interval: 15s
alerting:
  alertmanagers:
    - static_configs:
        - targets: ["alertmanager:9093"]
rule_files:
  - /etc/prometheus/alert.rules.yml
scrape_configs:
  # 你的應用(請按你的實際位置改 host:port)
  - job_name: "app"
    static_configs:
      - targets:
          - "app:8000" # 抓本機 8000
          # 或 "app:8000" 如果你的 app 也在 compose network 裡
    metrics_path: /metrics
  # 監控自己(Prometheus)
  - job_name: "prometheus"
    static_configs:
      - targets: ["prometheus:9090"]
  # 測試用的假目標
  - job_name: "fake"
    static_configs:
      - targets: ["127.0.0.1:9999"]
(c) monitoring/alert.rules.yml
兩條規則:InstanceDown 與 HighLatency。
groups:
  - name: core-alerts
    rules:
      # 服務抓不到(ex: app 掛了 / 網路斷)
      - alert: InstanceDown
        expr: up == 0
        for: 15s
        labels:
          severity: critical
        annotations:
          summary: "Target is down: {{ $labels.job }} {{ $labels.instance }}"
          description: "Prometheus cannot scrape {{ $labels.instance }} (job={{ $labels.job }}) for 2m."
      # P95 延遲 > 0.8 秒,持續 5 分鐘
      - alert: HighLatency
        expr: |
          histogram_quantile(
            0.95,
            sum(rate(http_request_latency_seconds_bucket[5m])) by (le)
          ) > 0.8
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "High p95 latency"
          description: "p95 latency > 0.8s for 5m. Check upstream/downstream bottlenecks."
(d) monitoring/alertmanager.yml
把告警送到 Email
global:
  resolve_timeout: 5m
  smtp_smarthost: 'smtp.gmail.com:587'
  smtp_from: 'hacuba7777@gmail.com'
  smtp_auth_username: 'hacuba7777@gmail.com'
  smtp_auth_password: '${GMAIL_APP_PASSWORD}'
  smtp_require_tls: true
  smtp_hello: 'app.hacuba.site'     
route:
  receiver: email
  group_by: ['alertname']
  group_wait: 10s
  group_interval: 1m
  repeat_interval: 5m
receivers:
  - name: email
    email_configs:
      - to: 'hacuba7777+am@gmail.com'
        hello: 'app.hacuba.site'    
        auth_identity: 'hacuba7777@gmail.com'   # 有些伺服器對 LOGIN/PLAIN 的 identity 會挑
        require_tls: true
        send_resolved: true
(e) .env(放 repo 根目錄;別忘了 .gitignore)
把你的 GMAIL_APP_PASSWORD 放這。
申請 Google 應用程式密碼步驟:
ENVIRONMENT=dev
GMAIL_APP_PASSWORD=xxxxxxxxxxxxxxxx #16碼
docker compose -f docker-compose.monitor.yml up -d
開起服務:
Prometheus UI → Status > Targets,應該看到 app 是 UP。
確認 docker 有順利起來,注意 prometheus 和 alertmanager 對應的 port 有映射正確
確認 prometheus 的 targets 頁面
確認 alertmanager 的告警頁面
如果沒意外也會收到告警信
到這裡,我們已經正式從「程式跑得起來」邁向「程式看得到狀態」。
/healthz 是血條,/metrics 是角色面板,而 Prometheus + Alertmanager 則是那個在背後敲鑼打鼓、提醒你「快補血」的隊友。
Devsecops的精神:不是只有跑起來就好,而是能監控、能預警,才算是真的安全上線。
因為在實務上,災難往往不是一瞬間爆炸,而是早就有徵兆:
透過 Metrics、監控與告警,我們不再只是「出事才搶救」,而是能「提前做反應」。
這差別,就像是被王一拳秒殺,跟隊伍提前喊「補師準備!」——結果天差地遠。
觀測能力 = 團隊的第六感。
沒有它,你永遠是在黑暗裡打王;有了它,你能看見數據的紅燈,提早踩煞車。